import std.stdio: writefln;
import std.string: toStringz;
import derelict.sdl.sdl;

import std.math;

import Pixels;
import ImageIO;
import ImageI;
import Images;
import PerceptronsMatrix;

const int   xResolution     = 640;
const int   yResolution     = 480;
const int   bitsPerPixel    = 32;
const int	imageIOWidth	= 50;
const int	imageIOHeight	= 50;
const int	scale			= 3;
const int	inputWindowX	= 100;
const int	inputWindowY	= 150;
const int	outputWindowX	= 400;
const int	outputWindowY	= 150;

SDL_Surface *screen;
ImageI imageIn;
ImageIO imageOut;
Images images;
PerceptronsMatrix perceptrons;

void init() {
    DerelictSDL.load();

    // initialize SDL's VIDEO module
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
    screen = SDL_SetVideoMode(xResolution, yResolution, bitsPerPixel, SDL_SWSURFACE );
    SDL_WM_SetCaption(toStringz("zad2"), null);
	setBackground(screen, 0x7F7F7F);
	imageIn = new ImageI(imageIOWidth, imageIOHeight, 0x000000, 0xFFFFFF);
	imageIn.dock(screen, inputWindowX, inputWindowY, scale);
	imageOut = new ImageIO(imageIOWidth, imageIOHeight, 0x000000, 0xFFFFFF);
	imageOut.dock(screen, outputWindowX, outputWindowY, scale);
	images = new Images(imageIOWidth, imageIOHeight, 0x000000, 0xFFFFFF);
	images.getNext(imageIn);
	perceptrons = new PerceptronsMatrix(imageIOWidth, imageIOHeight);
	perceptrons.train(images,1000);
}

void setBackground(SDL_Surface *surface, uint color){
	uint *pos = cast(uint*)(surface.pixels);
	pos[0..xResolution*yResolution] = color;
	SDL_UpdateRect(screen,0,0,0,0);
}


// be nice and release all resources
void cleanup() {
    SDL_Quit();
    DerelictSDL.unload();
}

void keyDown(SDL_KeyboardEvent e){
    if(e.keysym.sym == SDLK_ESCAPE) throw new Exception("KungFuDeathGrip");
	if(e.keysym.sym == SDLK_RIGHT) images.getNext(imageIn);
	if(e.keysym.sym == SDLK_LEFT) images.getPrevious(imageIn);
	if(e.keysym.sym == SDLK_a) images.addFromBox(imageIn);
	if(e.keysym.sym == SDLK_x) perceptrons.detect(imageIn, imageOut);
}

void drawFrame(){
	imageIn.draw();
	imageOut.draw();
}

void refresh(){
	SDL_UpdateRect(screen, inputWindowX - scale/2, inputWindowY - scale/2, imageIOWidth * scale + scale/2, imageIOHeight * scale + scale/2);
	SDL_UpdateRect(screen, outputWindowX - scale/2, outputWindowY - scale/2, imageIOWidth * scale + scale/2, imageIOHeight * scale + scale/2);

//	SDL_UpdateRect(screen,0,0,0,0);
}

void mouseButtonUp(SDL_MouseButtonEvent e){
    imageIn.keyUp(e.button);
}

void mouseButtonDown(SDL_MouseButtonEvent e){
    imageIn.keyDown(e.button);
}

void mouseMotion(SDL_MouseMotionEvent e){
    if ((e.x > (inputWindowX - 1) && e.x < (inputWindowX + imageIOWidth * scale )) &&
		(e.y > (inputWindowY - 1) && e.y < (inputWindowY + imageIOHeight* scale ))) {
        imageIn.mouseMotion(e.x - inputWindowX, e.y - inputWindowY);
    }
}


void main() {
	uint startTime;
	long frames;
    init();
//	writefln(SDL_MUSTLOCK(screen));
    scope(exit){
		writefln("\n Exiting.. \n %2.2f FPS\n",(cast(float)(frames)/(SDL_GetTicks()-startTime))*1000.f);
		cleanup();      // when we exit, perform cleanup
	}

	startTime = SDL_GetTicks();
    mainLoop:
    while (true) {
        SDL_Event event;

        // handle all SDL events that we might've received in this loop iteration
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
                // user has clicked on the window's close button
                case SDL_QUIT:
                    break mainLoop;
				case SDL_KEYDOWN:
					keyDown(event.key);
					break;
				case SDL_MOUSEBUTTONDOWN:
					mouseButtonDown(event.button);
					break;
				case SDL_MOUSEBUTTONUP:
					mouseButtonUp(event.button);
					break;
				case SDL_MOUSEMOTION:
					mouseMotion(event.motion);
					break;
                // by default, we do nothing => break from the switch
                default:
                    break;
            }
        }
	
	SDL_LockSurface(screen);
	drawFrame();
	SDL_UnlockSurface(screen);
	refresh();
//	SDL_UpdateRect(screen,0,0,0,0);
//	SDL_Flip(screen);
	frames++;
    }
}
